home *** CD-ROM | disk | FTP | other *** search
-
- ~4Dgifts/toolbox/src/exampleCode/smoke README
-
- Texture Mapped `smoke' special effects implementation
-
-
-
- to see the demo (with decent results), run the "cmdline" script.
- smokeNoTex is an executable built showing plain polygons (see Makefile).
-
-
-
- the rest of this file is the text portions of the Smoke.sc showcase file:
- -------------------------------------------------------------------------
-
-
- This program started out as a enhancement-request from General Dynamics
- to Deneb Robotics, for Deneb's factory-floor simulation products.
-
- There were two parts to the request:
-
- 1. a visualization of the source smoke or plume.
-
- 2. visualizing a compartment filling with smoke according to
- some rudimentary CFD calculations.
-
- I only focused on step 1, with a pointer to the `pfuSmoke' functionality
- inside our Performer product.
-
- Unfortunately, there were just too many technical hurdles to allow us
- (myself and the lead gfx programmer at Deneb) to utilize the Performer
- functionality directly.
-
- So, I took matters into my own hands and peeked in the source...
-
-
-
-
-
-
- The Performer utility code I looked at had:
-
-
- 1) an algorithm for translating single quad polygons along a direction
- vector over time while scaling the quad, and decreasing opacity
- (increasing transparency?)...
-
-
- void drawSmoke(uSmoke *smoke, uVec3 eye)
- {
- double now = uGetTime();
- double deltaTime, age = 1.0f;
- ...
- /* Compute time elapsed from previous uDrawSmoke */
- if(smoke->prevTime < 0.0f)
- deltaTime = 0.0f;
- else
- deltaTime = now - smoke->prevTime;
-
- if(smoke->duration > 0.0f)
- {
- age = 1.0 - (now - smoke->startTime) / smoke->duration;
- ...
- }
- ...
- puffInterval = smoke->puffInterval / age;
- puffDiss = smoke->dissipation/smoke->density * age;
-
- puff->t = (now - puff->startTime) / puffDiss;
-
- ...
- puff->transp = puff->t * puff->t * puff->t * puff->t;
-
- /* Radius is linear interpolation between radius and expansion */
- puff->radius = (1.0f - puff->transp) * smoke->radius +
- puff->transp * smoke->expansion * smoke->radius
- ...
- /* Translate puff based on velocity vector */
- tmp = puff->origin;
- uAddVec3(tmp, tmp, dist);
- ...
-
- if(smoke->tex) {
- uApplyTex(smoke->tex);
- }
-
-
- drawPuff(puff, smoke, eye);
- }
-
-
- void uApplyTex(uTexture *tex)
- {
- if(tex == NULL)
- {
- fprintf(stderr,"uApplyTex() Null uTexture.\n");
- return;
- }
- texbind(TX_TEXTURE_0, tex->index);
- }
-
-
-
-
-
-
- 2) code to cause all the quads to be rotated to face the eye-point in
- world coordinate space...
-
-
- void drawPuff(uPuff *puff, uSmoke *smoke, uVec3 eye)
- {
- ...
- /*
- * Compute matrix which rotates puff to face the eyepoint
- */
- uSubVec3(toEye, eye, puff->origin);
-
- uMakeRotOntoMat(mat, vec, toEye);
-
- for(i=0; i<4; i++)
- {
- uVec3 svert;
-
- /* Scale quad to current radius */
- uScaleVec3(svert, puff->radius, quad[i]);
-
- /* Offset puff based on radius */
- svert[1] -= smoke->radius;
-
- /* Rotate puff to follow viewer */
- uXformPt3(dquad[i], svert, mat);
-
- /* Translate puff to origin */
- uAddVec3(dquad[i], dquad[i], puff->origin);
-
- }
- ...
- }
-
- ***I know this part can and should be done by our hardware; I just haven't
- had time to finish the change.
-
-
-
-
-
-
- 3) a texture map with alpha-channel that would be modulated with the
- alpha value of the quad.
-
-
- void drawPuff(uPuff *puff, uSmoke *smoke, uVec3 eye)
- {
- uVec4 opaque;
- long i;
- ...
- #define Zv 0.0
- static float t2[]={1,0,Zv,1,1,Zv,0,1,Zv,0,0,Zv};
- ...
- uAddScaledVec3(opaque, smoke->bgnColor, puff->t, smoke->deltaColor);
-
- opaque[3] = 1.0f - puff->transp;
-
- ...
- #if NOTEXTURE
- #define T2F(t)
- #else
- #define T2F(t) t2f((t))
- #endif
-
- /*Draw a puff...finally*/
- lmcolor(LMC_DIFFUSE);
- c4f(opaque);
- bgnpolygon();
- cross(dquad[0],dquad[1],dquad[2],&norm[0],&norm[1],&norm[2]);
- norm_d[0]=(dquad[0][0]-norm[0]);
- norm_d[1]=(dquad[0][1]-norm[1]);
- norm_d[2]=(dquad[0][2]-norm[2]);
- n3f(norm);
- T2F(t2);
- v3f(dquad[0]);
- T2F(t2+3);
- v3f(dquad[1]);
- T2F(t2+6);
- v3f(dquad[2]);
- T2F(t2+9);
- v3f(dquad[3]);
- endpolygon();
-
- #if NOTEXTURE
- bgnline();
- v3f(dquad[0]);
- v3f(norm_d);
- endline();
- #endif
- }
-
-
-
-
-
-
- There were two stumbling blocks for me, using the smoke utility:
-
- 1) finding out how to properly setup the texture mapping properties
- and the texture environment.
-
- So, with a little help from some 4Dgifts code that worked...
-
-
- /*
- * Parameters for texturing.
- */
- float texps[] =
- { TX_MAGFILTER, TX_BILINEAR,
- TX_MINFILTER, TX_MIPMAP_BILINEAR,
- TX_WRAP_S, TX_CLAMP,
- TX_WRAP_T, TX_CLAMP,
- TX_NULL
- };
-
- float tevps[] = {TV_MODULATE,TV_NULL};
-
-
- 2) Determining what values to use for afunction(), blendfunc(), and
- zwritemask():
-
- Thanks to the Performer source tree, i was able to construct the
- following:
-
- void uDrawSmokes(uVec3 eye)
- {
- long i, n;
-
-
- zwritemask(0x00000000);
- if (UGET_GFX_TYPE() & PFGFX_HPC_40NS) /*express gfx*/
- afunction(0,AF_NOTEQUAL);
- else
- afunction(40,AF_GREATER);
-
- blendfunction(BF_SA, BF_MSA);
-
- n = smokeCount;
- for(i=0; i<n; i++) {
- if(smokeList[i]->mode != USMOKE_STOP) {
- drawSmoke(smokeList[i], eye);
- }
- }
-
- blendfunction(BF_ONE, BF_ZERO);
- zwritemask(0xffffffff);
-
- }
-
-
-
-
-
-
- Creating the textures for stand-alone 'smoke' was alot easier than
- trying to do it through the full-blown performer interface:
-
- in uTex.c...
-
- long uLoadTexFile(uTexture *tex, char *name)
- {
- IMAGE *image_in;
- char path[_MAXSTRING];
- long ret;
-
- if(tex == NULL)
- {
- fprintf(stderr,"uLoadTexFile() Null uTexture.\n");
- return -1;
- }
- if(!uFindFile(name, path, R_OK))
- {
- fprintf(stderr,"uLoadTexFile: could not find image file %s\n",name);
- return FALSE;
- }
- if ((image_in = iopen(path, "r")) == NULL)
- {
- fprintf(stderr,"uLoadTexFile: could not load image %s\n", name);
- return FALSE;
- }
-
- ret = uBuildTex(tex, name, image_in);
-
- iclose(image_in);
- return ret;
- }
-
- in main.c...
- void add_fire_tex(void)
- {
- fireTex = uNewTex();
- uLoadTexFile(fireTex, "fire.texture");
-
- texdef2d(fireTex->index,fireTex->comp,fireTex->sx,fireTex->sy,
- (unsigned long *)fireTex->image,0,texps);
- }
-
- void inittex(void)
- {
- smokeTex = uNewTex();
- uLoadTexFile(smokeTex, "smoke.texture");
-
- texdef2d(smokeTex->index,smokeTex->comp,smokeTex->sx,smokeTex->sy,
- (unsigned long *)smokeTex->image,0,texps);
-
- add_fire_tex();
-
- tevdef(1,2,tevps);
- tevbind(0,1);
- }
-
-
-
-
-
-
-